﻿using System;
using System.Collections.Generic;
using System.Windows;
using TextBox = System.Windows.Controls.TextBox;

namespace Elca.MvvmHelpers {

    public interface IDropTarget {

        void HandleDragOver(DragEventArgs dea);

        void HandleDrop(DragEventArgs dea);
    }

    /// <summary>
    /// Allows binding to drag&drop stuff (more precisely the drop stuff).
    /// Inspired by http://code.google.com/p/gong-wpf-dragdrop/
    /// </summary>
    public class DropHelper {

        private readonly static List<FrameworkElement> s_knownElements = new List<FrameworkElement>();

        public static readonly DependencyProperty DropHandlerProperty =
                DependencyProperty.RegisterAttached(
                        "DropHandler", typeof (IDropTarget), typeof (DropHelper),
                        new UIPropertyMetadata(OnDropHandlerPropertyChanged));


        public static IDropTarget GetDropHandler(FrameworkElement obj) {
            return (IDropTarget)obj.GetValue(DropHandlerProperty);
        }

        public static void SetDropHandler(FrameworkElement obj, IDropTarget value) {
            obj.SetValue(DropHandlerProperty, value);
        }

        private static void OnDropHandlerPropertyChanged(DependencyObject d,
                                                         DependencyPropertyChangedEventArgs e) {
            var fe = (FrameworkElement) d;


            if (e.NewValue != null) {

                if (! s_knownElements.Contains(fe)) {
                    HookHandlers(fe);
                    s_knownElements.Add(fe);
                }
                fe.AllowDrop = true;
            }
        }

        private static void HookHandlers(FrameworkElement fe) {
            fe.Unloaded += OnUnloaded;
            fe.DragOver += OnDragOver;
            fe.Drop += OnDrop;
        }

        private static void OnDragOver(object sender, DragEventArgs dea) {

            FrameworkElement fe = (FrameworkElement)sender;
            IDropTarget dt = GetDropHandler(fe);
            dt.HandleDragOver(dea);
        }

        private static void OnDrop(object sender, DragEventArgs dea) {
            FrameworkElement fe = (FrameworkElement)sender;
            IDropTarget dt = GetDropHandler(fe);
            dt.HandleDrop(dea);
        }

        private static void OnUnloaded(object sender, RoutedEventArgs e) {
            FrameworkElement fe = (FrameworkElement)sender;
            UnhookHandlers(fe);
            s_knownElements.Remove(fe);
        }

        private static void UnhookHandlers(FrameworkElement fe) {
            fe.Unloaded -= OnUnloaded;
            fe.DragOver -= OnDragOver;
            fe.Drop -= OnDrop;
        }
    }
}
